#include "Main.h"

DWORD __declspec(naked) GetUnitArray()
{
	__asm 
	{
		MOV ECX, 1
		XOR EDX, EDX
		CALL GAME_GetUnitArray_I // Game.6F0F5C60
		TEST EAX, EAX
		MOV ECX,DWORD PTR DS:[EAX+0x3BC]
		PUSH 0
		CALL GAME_GetUnitArray_II //Game.6F17FC60
		MOV EAX, [EAX+0x8]
		RETN
	}
}

DWORD __declspec(naked) GetUnitArraySize()
{
	__asm 
	{
		MOV ECX, 1
		XOR EDX, EDX
		CALL GAME_GetUnitArray_I // Game.6F0F5C60
		TEST EAX, EAX
		MOV ECX,DWORD PTR DS:[EAX+0x3BC]
		PUSH 0
		CALL GAME_GetUnitArray_II //Game.6F17FC60
		MOV EAX, [EAX+0x4]
		RETN
	}
}

// Thanks to sd3332221
DWORD __declspec(naked) GAME_GetItemArray() 
{ 
     __asm 
     { 
          XOR ECX, ECX 
          XOR EDX, EDX 
          CALL GAME_GetUnitArray_I // Game.6F0F5C60
          TEST EAX, EAX 
          MOV ECX,DWORD PTR DS:[EAX+0x3B0] 
          LEA ECX,DWORD PTR DS:[ECX+0x610] 
          MOV EAX,DWORD PTR DS:[ECX+8] 
          RETN 
     } 
}

DWORD __declspec(naked) __fastcall GAME_IsItemVisible_ASM(DWORD dwUnitPtr)
{
	__asm
	{
		MOV EAX,DWORD PTR DS:[ECX+0x20]
		NOT EAX
		AND EAX,1
		RETN
	}
}

DWORD GAME_IsChatBoxOpen()
{
	return (*p_GAME_ChatBoxPtr) ? 1 : 0;
}

// Well, this isn't really required when building, you need it to command units
// I will change the name once I am in the mood
// Note: in Patch 1.12 the "Pointer" is stored in the PointerList 
DWORD __declspec(naked) GetBuildingRequiredPtr()
{
	__asm 
	{
		CALL GAME_GetPtrList
		test eax, eax
		jz NAH
		MOV EAX, [EAX+0x24C]

		RETN
NAH:
		xor eax,eax
		RETN
		/*
		MOV EAX, [GAME_GetBuilding_I]
		MOV EAX, [EAX]
		MOV EAX, [EAX+0x1B4] // +0x24C from GAME_GetPtrList ..
		RETN
		*/
	}
}

BOOL __declspec(naked) __fastcall GAME_IsHero(DWORD dwClassId) 
{ 
     __asm 
     { 
        SHR ECX,0x18 
        CMP ECX,0x41 
        JL Game_6F2C9DAA 
        CMP ECX,0x5A 
        JG Game_6F2C9DAA 
        MOV EAX,1 
        RETN 
Game_6F2C9DAA: 
        XOR EAX,EAX 
        RETN    
     } 
}

DWORD __declspec(naked) InGame()
{
	__asm
	{
		CALL GAME_GetPtrList
		test eax, eax
		jz nah
		mov eax, [eax+0x1AC]
		retn
nah:
		xor eax,eax
		retn
	}
}

DWORD __declspec(naked) __fastcall GetSelectedUnitHelper(DWORD dwPtr)
{
	__asm
	{
		MOV ECX,DWORD PTR DS:[ECX+0x34]
		CALL GAME_GetSelectedUnit_I
		RETN
	}
}

Unit* GAME_GetSelectedUnit()
{
	Player* pPlayer = GAME_GetPlayer((*p_GAME_GameInfos), NULL, (*p_GAME_GameInfos)->wPlayerSlot);
	return (Unit*)GetSelectedUnitHelper((DWORD)pPlayer);
}

// From D2HackIt
DWORD GetDistance(DWORD x1, DWORD y1, DWORD x2, DWORD y2)
{
 	return (DWORD)sqrt((double)( ((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)))); 
}

// 0x50 -> Gold Amount
// 0x60 -> Lumber Amount
DWORD GetStatValue(DWORD dwPlayerSlot, DWORD dwList)
{
	PlayerInfo* pPlayerInfo = GAME_GetPlayerInfo(*p_GAME_GameInfos, NULL, dwPlayerSlot);

	if(!pPlayerInfo)
		return NULL;

	return GAME_GetPlayerStat((DWORD)pPlayerInfo + dwList);
}

VOID __declspec(naked) __fastcall GAME_CallUnitMaxLifeFunction(DWORD dwUnitPtrList, DWORD* pdwBuffer)
{
	__asm
	{
		MOV EAX, [ECX]
		PUSH EDX
		CALL [EAX+0x130]
		RETN
	}
}

VOID __declspec(naked) __fastcall GAME_CallUnitLifeFunction(DWORD dwUnitPtrList, DWORD* pdwBuffer)
{
	__asm
	{
		MOV EAX, [ECX]
		PUSH EDX
		CALL [EAX+0x12C]
		RETN
	}
}

DWORD GAME_GetUnitMaxLife(Unit* pUnit)
{
	DWORD dwLife = NULL;
	GAME_CallUnitMaxLifeFunction((DWORD)pUnit, &dwLife);
	return DecodeHealth(&dwLife);
}

DWORD GAME_GetUnitLife(Unit* pUnit)
{
	DWORD dwLife = NULL;
	GAME_CallUnitLifeFunction((DWORD)pUnit, &dwLife);
	return DecodeHealth(&dwLife);
}

DWORD  __declspec(naked) __fastcall DecodeHealth(DWORD* pdwHealth)
{
	__asm {
	PUSH ESI
	MOV ESI,DWORD PTR DS:[ECX]
	MOV EDX,ESI
	SHR EDX,0x17
	AND EDX,0xFF
	CMP EDX,0x7F
	JNB L010
	XOR EAX,EAX
	POP ESI
	RETN
	L010:
	MOV EAX,ESI
	AND EAX,0x7FFFFF
	MOV ECX,0x96
	OR EAX,0x800000
	SUB ECX,EDX
	JS L025
	SHR EAX,CL
	MOV ECX,ESI
	SAR ECX,0x1F
	POP ESI
	MOV EDX,EAX
	MOV EAX,ECX
	XOR EAX,EDX
	SUB EAX,ECX
	RETN
	L025:
	NEG ECX
	SHL EAX,CL
	MOV ECX,ESI
	SAR ECX,0x1F
	POP ESI
	MOV EDX,EAX
	MOV EAX,ECX
	XOR EAX,EDX
	SUB EAX,ECX
	RETN
	}
}

DWORD __declspec(naked) __fastcall GetAutomapPos_I(DWORD dwUnitAddr)
{
	__asm {
		MOV EAX, [ECX]
		MOV EAX, [EAX + 0xB8]
		CALL EAX
		RETN
	}
}

// Value is calculated like this:
//6F360DEB   2B87 28020000    |SUB EAX,DWORD PTR DS:[EDI+228]          ; dwX = dwX - pUnit->dwOffsetX; // +0x228


/*DWORD __declspec(naked) __fastcall GetMapQDWORDStuffX(DWORD dwValue, DWORD dwMapPtr)
{
	__asm {
		FILD DWORD PTR SS:[ECX] // 6F360E01   DB4424 0C  |FILD DWORD PTR SS:[ESP+C]
		FMUL DWORD PTR DS:[EDX+0x21C]//6F360E11   D88F 1C020000    |FMUL DWORD PTR DS:[EDI+21C]
			
		//		6F360E23   D95C24 14        |FSTP DWORD PTR SS:[ESP+14]


		MOV EAX, [GAME_qDWORDMapStuff]
		FLD QWORD PTR DS:[EAX]
	}
}*/

/*
GetAutomapPos routine:

6F360BF6   8D5424 18        |LEA EDX,DWORD PTR SS:[ESP+18]
6F360BFA   52               |PUSH EDX
6F360BFB   8B90 B8000000    |MOV EDX,DWORD PTR DS:[EAX+B8]
6F360C01   8BCB             |MOV ECX,EBX
6F360C03   FFD2             |CALL EDX
6F360C05   8BC8             |MOV ECX,EAX
6F360C07   E8 C43B1000      |CALL Game.6F4647D0                      ; GetUnitAutomapPos __fastcall (DWORD Ptr, DWORD _EDX, POINT* lpPos);
6F360C0C   8B4424 18        |MOV EAX,DWORD PTR SS:[ESP+18]
6F360C10   8B4C24 1C        |MOV ECX,DWORD PTR SS:[ESP+1C]
6F360C14   C1F8 02          |SAR EAX,2                               ; EAX >> 4;
6F360C17   C1F9 02          |SAR ECX,2                               ; ECX >> 4;
*/
DWORD __declspec(naked) __stdcall HelperTrick(float fValue)
{
	__asm {
		MOV EAX, [ESP + 4]
		SHR EAX, 0x0E
		MOVZX EAX,AL
		RETN 4 
	}
}


VOID GetAutomapPos(Unit* pUnit, POINT* lpPoint)
{
	MapData* pMap = *p_GAME_GlobalMapData;
	DWORD dwPtr = GetAutomapPos_I((DWORD)pUnit);
	floatStruct lpFloat;
	GAME_GetUnitAutomapPos(dwPtr, NULL, lpPoint);

	//0012F778  0E 00 00 00 18 00 00 00  ......
	// Step 1
	/*
		6F360C0C   8B4424 18        |MOV EAX,DWORD PTR SS:[ESP+18]
		6F360C10   8B4C24 1C        |MOV ECX,DWORD PTR SS:[ESP+1C]
		6F360C14   C1F8 02          |SAR EAX,2                               ; EAX >> 2;
		6F360C17   C1F9 02          |SAR ECX,2                               ; ECX >> 2;
	*/
	lpFloat.fX = lpPoint->x >> 2;
	lpFloat.fY = lpPoint->y >> 2;

	// Step 2
	/*
		6F360DEB   2B87 28020000    |SUB EAX,DWORD PTR DS:[EDI+228]          ; dwX = dwX - pUnit->dwOffsetX; // +0x228
		6F360E11   D88F 1C020000    |FMUL DWORD PTR DS:[EDI+21C]             ; Step 2
	*/
	lpFloat.fX = lpFloat.fX - pMap->fMapOffsetX;
	lpFloat.fY = lpFloat.fY - pMap->fMapOffsetY;

	lpFloat.fX *= pMap->fMapMultiplicatorX;
	lpFloat.fY *= pMap->fMapMultiplicatorY;
	// Step 3
	/*
		6F360E2F   DD05 808F926F    |FLD QWORD PTR DS:[6F928F80]             ; Step 3
		6F360E35   DCC1             |FADD ST(1),ST                           ; x + 6F928F80 value
	*/
	lpFloat.fX += 512.0000000000000;
	lpFloat.fY += 512.0000000000000;

	lpPoint->x = HelperTrick(lpFloat.fX) + pMap->dwMapAddX;
	lpPoint->y = 256 - HelperTrick(lpFloat.fY) + pMap->dwMapAddY;


/*
	lpPoint->x = (lpPoint->x >> 2);
	lpPoint->y = lpPoint->y >> 2;

	// Step 1
	float fX = lpPoint->x;
	float fY = lpPoint->y;
	
	fX -= pMap->fMapOffsetX;
	fY -= pMap->fMapOffsetY;
	// Step 2
	fX = fX * pMap->fMapMultiplicatorX;
	fY = fY * pMap->fMapMultiplicatorY;

	// Step 3
	fX += 512.0000000000000;
	fY += 512.0000000000000;

	// Step 4 & Step 5
	DWORD dwX  = HelperTrick(fX) + pMap->dwMapAddX;
	DWORD dwY  = HelperTrick(fY) + pMap->dwMapAddY;

	lpPoint->x = dwX;
	lpPoint->y = dwY;
	*/
}

VOID DrawPixel(DWORD dwX, DWORD dwY, DWORD dwColor)
{
	MapData* pMap = *p_GAME_GlobalMapData;
	pMap->dwMap[(dwY << 8) + dwX] = dwColor;
}

VOID DisplayInfoBox(CHAR* pTitle, CHAR* pText, CHAR* pText2)
{
	DWORD dwBoxPtr = *(DWORD*)(GAME_GetPtrList() + 0x1CC) ;
//	GAME_DrawBox();
/*
[[GetPtrList + 0x1CC] +0x90] -> DrawBox Flag

6F12E109   C786 88010000 02>MOV DWORD PTR DS:[ESI+188],2             ; Default case of switch 6F12E093
6F12E113   8B07             MOV EAX,DWORD PTR DS:[EDI]
6F12E115   C787 90000000 01>MOV DWORD PTR DS:[EDI+90],1

[GetPtrList + 0x1cc ] +  124] +0x188 auf 2 setzen
*/
//FUNCPTR(GAME, DrawBox, VOID __fastcall, (DWORD PtrList, DWORD _1, CHAR* pTitle, CHAR* pText1, CHAR* pText2, DWORD _2, DWORD _3, DWORD _4, DWORD _5), 0x158C20)
}

VOID SendPacket(BYTE* pPacket, DWORD dwSize)
{
	Packet aPacket;
	memset(&aPacket, NULL, sizeof(Packet));

	aPacket._6F921C14 = 0x6F921C14; // Packet Class
	aPacket.pPacket = pPacket;
	aPacket.dwSize = dwSize;
	aPacket._3 = 0xFFFFFFFF;
	GAME_SendPacket(&aPacket, NULL);
}

CHAR* GetIcon(DWORD dwRace)
{
	static CHAR szRace[][64] = {
		{""},
		{"ui\\feedback\\resources\\resourcehuman.blp"},
		{"ui\\feedback\\resources\\resourceorc.blp"},
		{"ui\\feedback\\resources\\resourceundead.blp"},
		{"ui\\feedback\\resources\\resourcenightelf.blp"},
	};

	return szRace[dwRace];
}

__declspec(naked) DWORD __fastcall GetPlayerStartLocationX(Player* pPlayer, float* fX)
{
	__asm
	{
		MOV EAX, ECX
		PUSH EDX
		CALL [GAME_GetPlayerStartLocX_I]
		POP EDX
		MOV [EDX], EAX
		RETN
	}
}

__declspec(naked) DWORD __fastcall GetPlayerStartLocationY(Player* pPlayer, float* fY)
{
	__asm
	{
		MOV EAX, ECX
		PUSH EDX
		CALL [GAME_GetPlayerStartLocY_I]
		POP EDX
		MOV [EDX], EAX
		RETN
	}
}

__declspec(naked) DWORD __stdcall GetUnitAnimationId(Unit* pUnit)
{
	__asm
	{
		XOR EAX, EAX
		PUSH ECX
		MOV ECX, [ESP+8]
		TEST ECX, ECX
		JZ Exit
		MOV ECX, [ECX+0x28]
		TEST ECX, ECX
		JZ Exit
		ADD ECX, 0x34
		CALL [GAME_GetUnitAnimationid_I]
		TEST EAX, EAX
		JZ Exit
		MOV EAX, [EAX]
Exit:
		POP ECX
		RETN 4
	}
}